package org.manager.generic.web;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import net.sf.json.util.PropertyFilter;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.validation.BindingResult;
import org.springframework.web.servlet.ModelAndView;



public class JsonViewUtil {
	
	protected static final Log log = LogFactory.getLog(JsonViewUtil.class);
	
	public static final String JSON_CONF = "json_conf";
	public static final String SUCCESS = "success";
	public static final String FAILURE = "failure";
	public static final String VIEW_NAME = "jsonView";
	public static final String DATA_NAME = "data";
	public static final String OK = "true";
	public static final String Err_MSG = "errMsg";

	public static Map<String,Object> getSuccessMap(){
		Map<String,Object> map = new HashMap<String,Object>();
		setSuccess(map);
		return map;
	}
	
	public static Map<String,Object> getSuccessMap(Object data){
		Map<String,Object> map = getSuccessMap();
		map.put(DATA_NAME, data);
		return map;
	}
	
	public static Map<String,Object> getFailureMap(){
		Map<String,Object> map = new HashMap<String,Object>();
		setFailure(map);
		return map;
	}
	
	public static Map<String,Object> getFailureMap(String errMsg){
		Map<String,Object> map = getFailureMap();
		map.put(Err_MSG, errMsg);
		return map;
	}
	
	public static void setSuccess(Map<String,Object> map){
		map.put(SUCCESS, OK);
	}
	
	public static void setFailure(Map<String,Object> map){
		map.put(FAILURE, OK);
	}
	
	public static ModelAndView getSuccessView(){
		//return new ModelAndView(VIEW_NAME, getSuccessMap());
		return getSuccessViewWithRule(getSuccessMap(),new Rule(),false);
	}
	
	public static ModelAndView getFailureView(){
		return getSuccessViewWithRule(getFailureMap(), new Rule(), false);
	}
	
	public static ModelAndView getFailureView(String errMsg){
		return new ModelAndView(VIEW_NAME, getFailureMap(errMsg));
	}
	
	public static ModelAndView getSuccessView(Object data, JsonRule jsonRule){
		return getSuccessView(data, jsonRule, false);
	}
	
	public static ModelAndView getSuccessView(Object data, JsonRule jsonRule, boolean onlyOutputDataAsArray){
		Rule rule = new Rule();
		jsonRule.roleCallback(rule);
		return getSuccessViewWithRule(data, rule, onlyOutputDataAsArray);
	}
	
	public static ModelAndView getSuccessViewWithIncludProperty(Object data, String includePropertys[]){
		return getSuccessViewWithIncludProperty(data, includePropertys, false);
	}
	
	
	public static ModelAndView getSuccessViewWithIncludProperty(Map<String,Object> map, String includePropertys[]){
		Rule rule = new Rule();
		rule.setIncludePropertys(includePropertys);
		return getSuccessViewWithRule(map, rule, false);
	}
	
	public static ModelAndView getSuccessViewWithStringDataArray(String data){
		return getSuccessViewWithIncludProperty(data, new String[0], true);
	}
	
	public static ModelAndView getSuccessViewWithIncludProperty(Object data, String includePropertys[], boolean onlyOutputDataAsArray){
		Rule rule = new Rule();
		rule.setIncludePropertys(includePropertys);
		return getSuccessViewWithRule(data, rule, onlyOutputDataAsArray);
	}
	
	public static ModelAndView getSuccessViewWithExcludProperty(Object data, String excludePropertys[]){
		return getSuccessViewWithExcludProperty(data, excludePropertys, false);
	}
	
	public static ModelAndView getSuccessViewWithExcludProperty(Object data, String excludePropertys[], boolean onlyOutputDataAsArray){
		Rule rule = new Rule();
		rule.setExcludeProperty(excludePropertys);
		return getSuccessViewWithRule(data, rule, onlyOutputDataAsArray);
	}
	
	private static ModelAndView getSuccessViewWithRule(Object data, Rule rule, boolean dataAsJsonString){
		Map<String,Object> map = getSuccessMap();
		if(dataAsJsonString && data == null){
			log.error("虽然指定onlyOutputDataAsArray为true,但并没有包含Data数据.");
			return new ModelAndView(VIEW_NAME, map);
		}
		map.put(DATA_NAME, data);
		return getSuccessViewWithRule(map, rule, dataAsJsonString);
	}
	
	private static ModelAndView getSuccessViewWithRule(Map<String,Object> map, Rule rule, boolean dataAsJsonString){
		rule.setSystemIncludeProperty(mapKey2StringArray(map));
		RuleJsonConfig config = createJsonConfig(rule);
		config.setDataAsJsonString(dataAsJsonString);
		map.put(JSON_CONF, config);
		return new ModelAndView(VIEW_NAME, map);
	}
	
	
	private static String[] mapKey2StringArray(Map<String, Object> map){
		Set<String> keySet = map.keySet();
		int size = keySet.size();
		String propertyArray[] = new String[size];
		Iterator<String> it=keySet.iterator();
		for(int i=0; i<size&&it.hasNext(); i++){
			propertyArray[i] = it.next();
		}
		return propertyArray;
	}
	
	
	protected static RuleJsonConfig createJsonConfig(final Rule rule){
		RuleJsonConfig config = new RuleJsonConfig();
		config.setJsonPropertyFilter(new PropertyFilter() {
			public boolean apply(Object source, String name,Object value) {
				if(rule == null){
					return true;
				}
				if(rule.isExclude(name)){
					return true;//忽略.
				}
				if(rule.isInclude(name)){
					return false;
				}
				
				if(!rule.isDefultExclude() && name.startsWith(BindingResult.class.getName())){
					return true;
				}
				
				return rule.isDefultExclude();
			}
		});
		return config;
	}
	
	
}
